namespace study4_05 {

    // is 关键字
    // 主要用于定义自定义的类型保护函数，返回布尔值。

    // 基本概念
    // 自定义类型保护函数的返回类型通常是一个类型谓词，使用is关键字来描述。
    // 当这个函数返回true时，ts会将该变量视为特定类型

    // 语法
    // function isSpecificType(value: any): value is SpecificType {
    //     // 检查逻辑
    // }
    // value is SpecificType 表明：如果函数返回 true，TypeScript 将认为 value 是 SpecificType 类型。


    // 使用is 关键字的类型保护函数
    // 这种函数常用于联合类型或复杂的检查，使得ts可以在某个代码分支中正确推断变量的类型

    // 示例1：简单的类型检查

    interface Cat {
        meow(): void
    }
    interface Dog {
        bark(): void
    }

    // isCat函数检查animal是否具有meow方法，如果有，则animal时Cat类型
    function isCat(animal: Cat | Dog): animal is Cat {
        return (animal as Cat).meow !== undefined
    }

    // 在makeSound函数中，当isCat(animal)返回true时，可知animal是Cat类型，因此可以安全地调用meow方法
    function makeSound(animal: Cat | Dog) {
        if (isCat(animal)) {
            animal.meow()
        } else {
            animal.bark()
        }
    }

    // 示例2：处理联合类型
    type Fish = {
        swim(): void
    }
    type Bird = {
        fly(): void
    }
    function isFish(pet: Fish | Bird): pet is Fish {
        return (pet as Fish).swim !== undefined
    }
    function move(pet: Fish | Bird) {
        if (isFish(pet)) {
            pet.swim()
        } else {
            pet.fly()
        }
    }

    // 在这个例子中，isFish函数用于检测pet是否为Fish类型，从而在move函数中精确控制类型


    // 复杂类型保护
    // 有时，类型保护可能涉及更多的属性检查或复杂的逻辑。
    // is 关键字使你能够封装这些复杂的检查逻辑，使代码更加可读和易维护

    // 示例3：检查多个属性

    // 正方形接口
    interface Square {
        kind: 'square'
        size: number
    }

    // 长方形接口
    interface Rectangle {
        kind: 'Rectangle'
        width: number
        height: number
    }
    // 形状接口
    type Shape = Square | Rectangle

    function isRectangle(shape: Shape): shape is Rectangle {
        return shape.kind === 'Rectangle'
    }

    function getArea(shape: Shape) {
        if (isRectangle(shape)) {
            return shape.width * shape.height
        } else {
            return shape.size * shape.size
        }
    }
    // isRectangle 函数通过 kind 属性来识别 Rectangle，从而在 getArea 函数中提供精确的类型推断。


    // 总结：
    // 1、类型保护：is关键字用于定义类型保护函数，使ts能够在特定的代码中提供精确的类型推断
    // 2、自定义检查：可以工具业务逻辑自定义类型检查条件，以处理复杂的类型或联合类型
    // 3、提高代码可读性：通过封装复杂的类型逻辑，is关键字使代码更易读和易维护


    // 其他示例
    // 示例4：使用自定义类型保护
    // ts允许你定义自定义的类型保护，通过返回value is Type 的形式，明确告知编译器某个值的类型
    interface Fish2 {
        swim(): void
    }
    interface Brid2 {
        fly(): void
    }
    function isFish2(pet: Fish2 | Brid2): pet is Fish2 {
        return (pet as Fish2).swim !== undefined
    }
    function checkPet(pet: Fish2 | Brid2) {
        if (isFish2(pet)) {
            pet.swim()
        } else {
            pet.fly()
        }
    }


    // 示例5：使用in操作符
    // 判断某个属性是否存在于对象中，常用于联合类型判断
    interface Car {
        drive(): void;
    }

    interface Boat {
        sail(): void;
    }

    function move2(vehicle: Car | Boat): void {
        if ("drive" in vehicle) {
            vehicle.drive();
        } else {
            vehicle.sail();
        }
    }

    // 示例6：使用===进行特定值判断
    // 对于特定的枚举类型或者字面量联合类型，可以使用严格相等进行判断
    type Direction = "up" | "down" | "left" | "right";
    function moveDirection(direction: Direction): void {
        if (direction === 'up') {
            console.log('moving up');

        } else if (direction === 'down') {
            console.log('move down');
        } else if (direction === 'left') {
            console.log('move left');

        } else {
            console.log('move right')
        }
    }



    // 使用switch语句
    // switch语句可以对联合类型或枚举类型的所有可能值进行全面处理
    enum Color {
        Red,
        Green,
        Blue
    }

    function chooseColor(color: Color): void {
        switch (color) {
            case Color.Red:
                console.log("Red color chosen.");
                break;
            case Color.Green:
                console.log("Green color chosen.");
                break;
            case Color.Blue:
                console.log("Blue color chosen.");
                break;
            default:
                console.log("Unknown color.");
                break;
        }
    }



}